home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
assemblr
/
library
/
sampler0
/
wild.asm
< prev
next >
Wrap
Assembly Source File
|
1988-03-16
|
38KB
|
853 lines
; WILD Public Domain 1988 by Charles Lazo III, v1.0
; WILD.ASM This program is used to run any other program (or DOS command)
; by expanding program wild card parameters given on the command
; line. E.g., WILD PROG *.* would run a program, say PROG.EXE,
; multiple times and supply it each time with a file from the
; current directory matching *.* (i.e., every file in the current
; directory would be supplied to PROG for execution).
rt equ 0dh
lf equ 0ah
of equ offset
bptr equ byte ptr
wp equ word ptr
code segment
assume cs:code, ds:code
org 2ch
env_seg dw ? ; pointer to segment of our environment
org 100h
begin: jmp start
;-------------------------------------------------------------------------------
; The wild card specification is placed here at the bottom of our stack to avoid
; having to specially set aside space for it. It is used by the find_first
; routine to find the first file in the current directory meeting the wild card
; specification using the DOS Find First function.
;-------------------------------------------------------------------------------
wild_spec db 16 dup('STACK ') ; 128 bytes for stack
our_stack label word
ss_save dw ? ; place to store ss:sp
sp_save dw ?
memory_used dw ? ; keep track of memory paragraphs used
env_size dw ? ; number of bytes in the environment stored here
cspc_addr label dword
dw 2 dup(?); store address of comspec variable here
left_blank dw ? ; stores pointer to start of wild card spec
right_blank dw ? ; stores pointer to end of wild card spec
copy_size dw ? ; stores size of command on command line (WILD)
buffer_ptr dw 0 ; pointer to buffer for list of filenames
switches db 0 ; record presence of QUERY & NOEXT here
file_attr dw 0 ; store file attributes for file find
cmd_line db 128 dup(0) ; save original command line here
cmdl db ?,'/c',128 dup(?) ; command line for EXEC
;-------------------------------------------------------------------------------
; The parameter table to be passed to the DOS EXEC function:
;-------------------------------------------------------------------------------
params dw ? ; segment of environment block stored here
dw of cmdl ; offset of command line for program EXECed
dw ? ; segment of command line for program EXECed
dw 55h ; offset of first FCB
dw ? ; segment of first FCB
dw 65h ; offset of second FCB
dw ? ; segment of second FCB
;*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
; The following routines (up to the label buffer:) operate under the assumption
; that both ds and es are set to the code segment of WILD.
;*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
;-------------------------------------------------------------------------------
; When the WILD environment variable has NOEXT in its assignment string, then
; filename extensions are ignored (not supplied) when commands are passed to
; the DOS EXEC function. This routine will remove any extension from the file-
; name in the DTA placed there by the DOS Find First and Continue File Search
; functions if NOEXT was found in the WILD environment variable. The extension
; is removed by replacing the period separating the main part from the extension
; with a null. Note that if a period is the only part of the filename, then it
; must be the dot representing the current directory so it is not removed.
;-------------------------------------------------------------------------------
remove_ext? proc near ; removes any extension from filename
test switches,noe ; is WILD NOEXT env variable set?
jz no_remove ; no, don't remove extension
xor al,al ; find null terminating filename
mov cx,14 ; max number of characters in ASCIIZ+1
cld ; (for maintenance and documentation)
repne scasb ; search for null
sub di,9eh ; compute number of filename characters
mov cx,di ; and place it in cx for next search
mov al,'.' ; search for period prior to extension
mov di,9eh ; offset of filename in DTA
repne scasb ; search for period
jcxz no_remove ; can't remove extension if not there
cmp di,9fh ; if the period was the ONLY character,
jz no_remove ; then it is the current directory
mov bptr [di-1],0 ; set it to null to remove the extension
no_remove: ret
remove_ext? endp
;-------------------------------------------------------------------------------
; find_size computes the length of a filename in the DTA placed there by the DOS
; find first and continue file search functions. The length of the filename is
; returned in cx (the null character at the end of the ASCIIZ string is included
; in the count). This routine is similar to file_size, qv.
;-------------------------------------------------------------------------------
find_size proc near ; find size of filename (returned in cx)
call remove_ext? ; eliminate filename extension?
xor al,al ; find null at end of ASCIIZ filename
mov di,9eh ; offset of filename in DTA
mov cx,14 ; max number of characters in ASCIIZ+1
cld ; (for maintenance and documentation)
repne scasb ; search for null in ASCIIZ filename
sub di,9eh ; compute number of filename characters
mov cx,di ; return value in cx
ret
find_size endp
;-------------------------------------------------------------------------------
; In this routine we check to see if there is enough memory presently allocated
; for the filename buffer to place another filename in the buffer. First di is
; is set to the location in the buffer where the next filename will go. If not
; enough memory has been allocated to allow the placement of another filename
; in the buffer, then more memory is allocated. By using only the memory that
; is needed by the buffer (additional memory is allocated in blocks of 16 para-
; graphs or 256 bytes; an arbitrary value) the remaining memory can be used in
; the EXEC call.
;-------------------------------------------------------------------------------
set_di proc near ; sets di to point to next available
mov di,buffer_ptr ; location in filename buffer
push cx ; save filename size
or di,di ; is it zero (uninitialized)?
jz init_di ; yes, point it to start of buffer
mov bx,di ; use bx to find paragraphs used now
add bx,0fh ; round up to next paragraph
shr bx,1 ; determine paragraph count
shr bx,1
shr bx,1
shr bx,1
inc bx ; reserve one more than used
mov ax,memory_used ; memory paragraphs presently allocated
cmp bx,ax ; is memory to be used > allocated?
ja get_more ; yes, get more memory
di_set: pop cx ; restore filename size
ret
get_more: add ax,16 ; ask for 256 more bytes (16 paragraphs)
mov bx,ax ; request sent in bx
mov dx,ax ; store in dx to assure request granted
mov ah,4ah ; DOS memory modify function (es is ok)
int 21h ; ask DOS for it
cmp bx,dx ; DOS give what we wanted?
mov dx,of mem_need ; address error message in case not
jz got_it ; got requested memory
jmp error_exit ; nope, DOS don't have it, terminate
init_di: mov di,of buffer
jmp short di_set ; exit with di at start of buffer
got_it: mov memory_used,bx ; update memory allocated
pop cx ; restore filename size
ret
set_di endp
;-------------------------------------------------------------------------------
; With this call we copy the filename in the DTA (placed there by DOS Find First
; and Continue File Search functions) into the filename buffer.
;-------------------------------------------------------------------------------
store_filename proc near ; store filename of file find in buffer
call find_size ; find size of filename in DTA (to cx)
call set_di ; set di to next location in buffer
mov si,9eh ; offset of filename in DTA
cld ; (for maintenance and documentation)
rep movsb ; move ASCIIZ filename to buffer
mov buffer_ptr,di ; update buffer pointer
ret
store_filename endp
;-------------------------------------------------------------------------------
; This one is similar to the find_size routine in that the size of a file is
; returned in cx. While the find_size routine gets its input from the filename
; in the DTA, this one finds sizes of filenames set into the filename buffer.
; Additionally it differs in that find_size includes the terminal null in the
; count and this one does not. Also the zero flag is set if no more filenames
; exist (else reset).
;-------------------------------------------------------------------------------
file_size proc near ; size of next filename in buffer to cx
mov di,buffer_ptr ; get current buffer position
cmp bptr [di],0 ; was the last the final filename?
jz last_done ; yes, return with zero flag set
mov cx,di ; save current buffer position
push cx
mov cx,14 ; longer than any ASCIIZ filename string
mov al,0 ; search for null in ASCIIZ filename
cld ; (for maintenance and documentation)
repne scasb ; find the null
mov buffer_ptr,di ; store new buffer position
pop cx ; recover last buffer position
sub di,cx ; compute size of filename in cx
xchg cx,di
dec cx ; discard null and reset the zero flag
last_done: ret
file_size endp
;-------------------------------------------------------------------------------
; A copy of the command line as given by the user (WILD's command line) is
; maintained at the location cmd_line. The variables left_blank and right_blank
; point to the first and last characters of the wild card specification within
; cmd_line when this routine is called the first time or the first and last
; characters of the previous filename when the routine is called at succeeding
; times. This blank is resized--either made larger or smaller--depending upon
; the size of the current filename that is to be copied into it.
;-------------------------------------------------------------------------------
resize_blank proc near ; adjust filename blank to right size
mov ax,left_blank ; first character of blank
mov bx,right_blank ; last character of blank
sub bx,ax ; compute length of blank
inc bx
mov di,right_blank ; point to last character of blank
mov al,rt ; search for return character
push cx ; save filename size
mov cx,127 ; larger than necessary, so ok
cld ; (for maintenance and documentation)
repne scasb ; find the return character
dec di ; point di to return character
mov cx,di ; compute number to move in cx
mov ax,right_blank
sub cx,ax
pop ax ; get filename size
cmp ax,bx ; greater, less than, or equal?
je rb_done ; finished if equal
jb decrease ; less than, so decrease blank
sub ax,bx ; compute amount filename is greater
mov si,di ; point si to return character
add di,ax ; di to new location of return character
std ; decrement move this time
rep movsb ; make room for filename
mov bx,right_blank ; adjust this variable
add bx,ax
mov right_blank,bx
mov bx,copy_size ; and this one also
add bx,ax
mov copy_size,bx
mov bl,cmd_line ; and this one too
add bl,al
mov cmd_line,bl
rb_done: ret
decrease: sub bx,ax ; compute amount blank is greater
mov si,right_blank ; point to first character after blank
inc si
mov di,si ; compute new location for these chars
sub di,bx
cld ; (for maintenance and documentation)
rep movsb ; resize blank to filename size
mov ax,right_blank ; adjust this variable
sub ax,bx
mov right_blank,ax
mov ax,copy_size ; and this one also
sub ax,bx
mov copy_size,ax
mov al,cmd_line ; and this one too
sub al,bl
mov cmd_line,al
ret
resize_blank endp
;-------------------------------------------------------------------------------
; cx contains filename size due to maintenance of this value on the stack while
; the resize_blank routine was called previous to the call to this one. The
; routine copies a filename from the filename buffer into a holding area (the
; location in cmd_line called blank) prior to it's being copied to the command
; line used by EXEC.
;-------------------------------------------------------------------------------
copy_filename proc near ; copy a buffer filename to cmd_line
mov si,buffer_ptr ; point si to current filename
sub si,cx ; (since file_size updated buffer_ptr
dec si ; we must go back for current file)
mov di,left_blank ; the place in cmd_line to copy to
cld ; (for maintenance and documentation)
rep movsb ; filename --> cmd_line
ret
copy_filename endp
;-------------------------------------------------------------------------------
; This routine prepares the next command line that will be passed to EXEC by
; using the next available filename from the filename buffer. If all filenames
; have been processed, then the zero flag is set on return, else it is reset.
;-------------------------------------------------------------------------------
copy_command proc near ; copy command to EXEC's command line
call file_size ; find size of filename (returned in cx)
jz all_done ; no more, so return with zero flag set
push cx ; save filename size
call resize_blank ; adjust filename blank to right size
pop cx ; restore filesize for copy_filename
call copy_filename ; filename from buffer --> command line
mov cx,copy_size ; get size of command line copy
mov al,cmd_line ; set size of EXEC's command line
add al,2 ; account for increase due to "/c"
mov cmdl,al ; set in size for EXEC
mov si,of cmd_line+1; copy command to be executed
mov di,of cmdl+3 ; to proper location for EXEC
cld ; (for maintenance and documentation)
rep movsb ; do the copy
or al,al ; al is nonzero so zero flag is reset
all_done: ret
copy_command endp
;-------------------------------------------------------------------------------
; If the WILD environment variable contains the QUERY option, then this routine
; prompts the user with "(Y/N/A)?" for Yes, No, or Abort. The zero flag is set
; on return if the user replies No, it is reset if the reply is Yes, and the
; carry flag is set if Abort is the reply (carry flag reset if Y or N). These
; flag settings are preserved by the calling routine, wild_prompt, so that the
; code that calls wild_prompt can test them. This code responds as if a Yes
; response were given if QUERY is not active.
;-------------------------------------------------------------------------------
wild_query? proc near ; inquire Yes, No, or Abort if QUERY set
test switches,que ; is QUERY set in switches variable?
jz wq_yes ; no, return to caller as if Yes
mov dx,of wq_prompt ; prompt to send to standard error
mov cx,wqp_size ; number of characters to send
mov bx,2 ; write to file handle 2 (std error)
mov ah,40h ; with DOS function 40h
int 21h
wq_next: mov ah,7 ; DOS keyboard input without echo
int 21h
or al,al ; an ASCII character?
jnz wq_ascii ; yes, process the response
mov ah,7 ; no, get and discard auxiliary byte
int 21h
jmp short wq_next ; continue input
wq_ascii: and al,0dfh ; capitalize
mov response,al ; and store it for (possible) output
cmp al,'Y' ; a Yes response?
je wq_yes ; uhuh, reset zero flag and exit
cmp al,'N' ; a No response?
je wq_no ; yeah, just exit (ZF is set)
cmp al,'A' ; an Abort response?
je wq_abort ; yep, set carry flag and exit
jmp short wq_next ; none of the above; try again
wq_yes: or al,al ; reset zero flag to indicate Yes
wq_no: pushf ; save flags
mov dx,of response ; write this
mov cx,1 ; one character
mov bx,2 ; to standard error
mov ah,40h ; with DOS function 40h
int 21h
popf ; recover return flags
ret
wq_abort: or al,al ; reset zero flag so not taken as No
stc ; set carry flag to indicate abort
jmp short wq_no ; write response to screen
wq_prompt db ' (Y/N/A)? ' ; prompt user with <(Yes, No, Abort)?>
wqp_size equ $-wq_prompt ; size of prompt
response db ? ; place to store user response to query
wild_query? endp
;-------------------------------------------------------------------------------
; Here we show the user the command that will be executed next by WILD and if
; the WILD environment variable contains the QUERY option, then we will prompt
; (Y/N/A)? also.
;-------------------------------------------------------------------------------
wild_prompt proc near ; output to std out the command EXECed
mov dx,of wild_pmt ; display "WILD>" lead in
mov cx,wildpmt_size ; size of lead in
mov bx,2 ; write to file handle 2 (std error)
mov ah,40h ; with DOS function 40h
int 21h
mov dx,of cmdl+3 ; point to command to be EXECed
mov cx,copy_size ; number of bytes to send to std out
dec cx ; but not the return at end of line
mov bx,2 ; write to file handle 2 (std error)
mov ah,40h ; with DOS function 40h
int 21h
call wild_query? ; send a query?
pushf ; save response
mov dx,of wild_rtlf ; return/linefeed to std out
mov cx,2 ; just 2 characters to send
mov bx,2 ; write to file handle 2 (std error)
mov ah,40h ; with DOS function 40h
int 21h
popf ; restore response
ret
wild_pmt db rt,lf,'WILD>' ; lead in for WILD
wildpmt_size equ $-wild_pmt
wild_rtlf db rt,lf ; newline after "prompt"
wild_prompt endp
find_rest: call store_filename ; store filename as ASCIIZ in buffer
mov ah,4fh ; DOS continue file search function
int 21h
or ax,ax ; return code nonzero?
jnz all_found ; yes, all files have been found
jmp short find_rest ; continue file find
all_found: mov di,buffer_ptr ; get file buffer pointer
mov bptr [di],0 ; double null indicates end of buffer
mov di,of buffer ; start now at beginning of buffer
mov buffer_ptr,di ; to process filenames
next_file: call copy_command ; copy command with filename to EXEC's
; copy of the command line
jz exit ; zero flag set indicates completion
call wild_prompt ; command to screen and maybe prompt
jz next_file ; user said no to this one
jc exit ; user wants to abort
mov ss_save,ss ; save stack to restore upon return from
mov sp_save,sp ; the EXEC
lds dx,cspc_addr ; ds:dx points to name of prog to EXEC
mov bx,of params ; es:bx points to parameter block
mov ax,4b00h ; execute program after loading it
int 21h
mov ss,cs:ss_save ; restore our stack
mov sp,cs:sp_save
mov ax,cs ; cs --> ds, es
mov ds,ax
mov es,ax
jmp short next_file
exit: mov ax,4c00h ; terminate with error code 0
int 21h
buffer: ; store list of ASCIIZ filenames here prior to processing
;*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
; The following routines will be used before the buffer is used and not again
; after the buffer begins to fill with ASCIIZ filenames from the current
; directory. Since memory is saved by overwriting them, that is why they are
; placed here. Even though this code and data will be overwritten as the file-
; name buffer begins to fill with files, the memory saved for the program's use
; includes all memory where this code and data reside. A filename buffer is
; used to store the names of files obtained from the current directory because
; after the EXEC function is used DOS somehow looses some of the information it
; needs for the performance of the Continue File Search function.
;*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
;-------------------------------------------------------------------------------
; We use this routine to check for the presence of a space, tab or the beginning
; of the command line in order to determine the location of the start of a wild
; card specification.
;-------------------------------------------------------------------------------
space_tab_left proc near ; return with Z flag set if di points to
cmp bptr [di],' ' ; a space
je stl_z
cmp bptr [di],9 ; a tab
je stl_z
cmp di,of cmd_line ; or the start of the command line
je stl_z
or al,al ; reset Z flag
stl_z: ret
space_tab_left endp
;-------------------------------------------------------------------------------
; Checks for invalid filename characters following a wild card character to
; signal the end of the wild card spec. Thus the space character--although it
; is not included in my PC DOS 3.20 manual as an invalid character (oversight?)
; --is included among them. Also the period, even though it is an invalid
; filename character is not included among those checked since it is valid as a
; character in a wild card specification (same with * and ?).
;-------------------------------------------------------------------------------
check_invalid proc near ; return with Z flag set if di points to
mov ah,[di] ; an invalid filename character
push ax ; save wild card test character
cmp ah,' ' ; space or less than?
jbe ci_z ; yes, return with zero flag set
mov si,of inv_chars ; point to set of invalid characters
cld ; (for maintenance and documentation)
get_inv: lodsb ; get one of these
or al,al ; end of invalid character set?
jz ci_nz ; yes, return with zero flag reset
cmp ah,al ; an invalid character
je ci_z ; yes, return with zero flag set
jmp short get_inv ; test another
ci_z: pop ax ; restore wild card test character
xor ah,ah ; set zero flag
ret ; return (zero flag is set)
ci_nz: pop ax ; restore wild card test character
or al,al ; reset zero flag
ret
inv_chars db '"/\[]:|< >+=;,',0 ; invalid filename characters
check_invalid endp
;-------------------------------------------------------------------------------
; This routine will find the wild card specification in the copy of the command
; line (cmd_line), execute the DOS find first function, place the filename
; obtained from this function into the command line copy (cmd_line), copy this
; command into the command line that will be passed to EXEC, and then return.
; The location of the wild card spec in cmd_line is referred to by the term
; "blank", since this is a "fill in the blank" operation.
;-------------------------------------------------------------------------------
find_first proc near ; find first file of wild card spec
mov al,rt ; search the end of command line first
mov di,81h ; start at first character
mov cx,127 ; maximum is fewer, but this will do
cld ; (for maintenance and documentation)
repne scasb ; find return character
sub di,81h ; compute number of characters to search
mov copy_size,di ; store here for later use
mov al,'*' ; first test for presence of an asterisk
search_wild: mov cx,copy_size ; install number of characters to search
mov di,of cmd_line+1; command line passed by DOS (copy)
cld ; (for maintenance and documentation)
repne scasb ; do search
jcxz not_this_wild ; this wild card not found
push di ; save position of char after wild card
dec di ; move to wild card
back_one: dec di ; test character left
call space_tab_left ; check for space, tab or beginning
jnz back_one ; go back a character and look again
inc di ; point to first character in blank
mov left_blank,di ; store position as start of blank
pop di ; points to character after wild card
dec di ; undone by next instruction
over_one: inc di ; test one character right
call check_invalid ; check if an invalid filename character
jnz over_one ; go forward a character and look again
dec di ; point to last character in blank
mov right_blank,di ; store position as end of blank
mov si,left_blank ; address blank for copy
mov cx,di ; construct size of blank in cx
inc cx
sub cx,si
mov di,of wild_spec ; copy blank (wild spec) here
cld ; (for maintenance and documentation)
rep movsb ; do the copy to work space
mov bptr [di],0 ; make it an ASCIIZ string
mov dx,of wild_spec ; address with ds:dx for find first
mov cx,file_attr ; find files with these attributes
mov ah,4eh ; DOS find first function
int 21h
or ax,ax ; return code nonzero?
jnz none_found ; yes, no files were found, return
xor ax,ax ; return code is zero
none_found: ret
not_this_wild: cmp al,'?' ; did we search for a "?" yet?
je no_wild ; yes, no other wild
mov al,'?' ; no, so search for it too
jmp short search_wild
no_wild: mov ax,255 ; return 255 if no wild card found
ret
find_first endp
cspc_str db 'COMSPEC=' ; COMSPEC string to find in environment
cspc_size equ $-cspc_str ; size of "COMSPEC=" string
notice db rt,lf,'WILD v1.0 Public Domain 1988 by Charles Lazo '
db 'III, CIS userid 72210,17',rt,lf
notice_size equ $-notice
bad_DOS db rt,lf,'WILD: Requires DOS version 2 or above.',rt,lf,0
mem_need db rt,lf,'WILD: Not enough memory.',rt,lf,0
no_comspec db rt,lf,"WILD: Can't find COMSPEC in environment."
db rt,lf,0
none_wild db rt,lf,'WILD: No wild card characters were found.'
db rt,lf,0
no_file db rt,lf,'WILD: No files were found.',rt,lf,0
;-------------------------------------------------------------------------------
; Execution is transferred here when an error has occured. The code that has
; transferred control here will place in dx the offset of the error message that
; will be sent to standard error. This error message must be terminated by a
; null. The program then exits with error level set to 1.
;-------------------------------------------------------------------------------
error_exit: mov ax,cs ; assure ds and es at cs
mov ds,ax
mov es,ax
mov di,dx ; find the null terminating error string
xor al,al ; search for null
cld ; (for maintenance and documentation)
mov cx,0ffffh ; largest possible
repne scasb ; find the null
mov cx,di ; compute number of characters to send
sub cx,dx ; in cx
dec cx
mov bx,2 ; send them to standard error
mov ah,40h ; with DOS function 40h
int 21h
mov ax,4c01h ; exit with error code 1
int 21h
;-------------------------------------------------------------------------------
; Execution comes here when the program begins. First the DOS version is
; checked to be sure it is 2 or greater, then all memory is released except that
; which is needed to continue operation after the filename buffer begins to fill
; with filenames from the current directory. (All code and data is retained,
; but that which lies beyond the label buffer: is overwritten by filenames as
; the filename buffer begins to fill. If more memory is needed, then it is
; allocated by the set_di routine.) The size of the environment is determined
; so that it can be used as a limit to the number of bytes to be searched for
; the two environment variables WILD and COMSPEC. Next the string "WILD=" is
; searched for in the environment and if found, then the two data variables,
; switches and file_attr (defined at the top of this file), are initialized
; based upon the settings in this string. Finally, the string "COMSPEC=" is
; searched for in the environment and if not found, the program sends a message
; to the screen and terminates with the error level set to 1. If COMSPEC is
; found its segment and offset are stored in the variable cspc_addr to be used
; later to find the program (usually COMMAND.COM) that shall be used as a shell
; to run the command given by the user.
;-------------------------------------------------------------------------------
start: mov dx,of bad_DOS ; prepare wrong version message
mov ah,30h ; get DOS version number
int 21h
cmp al,2 ; DOS ver 2 or greater?
jae DOS_ok ; yes, good DOS version
jmp short error_exit; else send error and exit
DOS_ok: mov dx,of notice ; show notice information
mov cx,notice_size ; length of notice message
mov bx,2 ; send notice message to standard error
mov ah,40h ; with DOS function 40h
int 21h
mov bx,of last ; assure all code retained
mov ax,of buffer ; assure at least 256 bytes for buffer
add ax,256
cmp bx,ax ; use the larger of these two
jae bx_good ; bx larger is good enough
mov bx,ax ; make bx good enough
bx_good: add bx,0fh ; round up to next paragraph
shr bx,1 ; calculate paragraphs
shr bx,1
shr bx,1
shr bx,1
mov memory_used,bx ; save here for later use
mov ah,4ah ; DOS modify block to reserve bx
int 21h ; paragraphs for code and buffer
mov dx,memory_used ; get number requested
cmp bx,dx ; is number available same as requested?
mov dx,of mem_need ; address memory needed error
jz modify_ok ; okay, on modify memory block
jmp error_exit ; error, not able to modify block
modify_ok: mov sp,of our_stack ; move stack to memory owned by us
mov si,80h ; offset of command line given us by DOS
mov di,of cmd_line ; place to copy command line (it is
cld ; overwritten by DOS find file calls)
mov cx,128 ; copy 128 bytes (DOS legal limit)
rep movsb
mov ax,env_seg ; get segment of environment
mov params,ax ; and place it in parameter table
mov params+4,cs ; segment of command line
mov params+8,cs ; segment of first FCB
mov params+12,cs ; segment of second FCB
jmp find_env_size ; determine size of environment
;-------------------------------------------------------------------------------
; This one searches the environment for the string pointed to by es:di. The
; number of characters in the string is provided in dx, bx has the number of
; bytes to be searched and ds:si points to the starting point of the search.
; If the string is found, then the carry flag is reset to indicate success and
; the offset of the string into the segment of the environment is returned in
; si. If the search fails, then the carry flag is set prior to return.
;-------------------------------------------------------------------------------
search_str proc near ; search environment for string at di
mov cx,bx ; set number of bytes to search
next_byte: push cx ; save number of bytes to search
push si ; save start positions
push di
mov cx,dx ; number of characters in string at di
cld ; (for maintenance and documentation)
repe cmpsb ; compare the two strings
jcxz str_found ; found string at di in the environment
pop di ; get 'em back
pop si
inc si ; bump pointer
pop cx ; get count
loop next_byte
stc ; set carry; string at di not found
ret
str_found: pop di ; remove stacked registers
pop si
pop cx
clc ; clear carry; string at di found
ret
search_str endp
;-------------------------------------------------------------------------------
; Here we search for the meaningful values that may be contained in the WILD
; environment variable. These values are QUERY, NOEXT, H, S, and D (capital-
; ization is not significant). The file WILD.DOC gives a description of the
; meaning of each. First the whole string is capitalized and then a search is
; made for QUERY and for NOEXT. The first and/or second bit of the byte
; switches is set depending upon the success of these searches. Then H(idden),
; S(ystem) and D(irectory) values are searched and if found, then corresponding
; bits are set in the file_attr variable. Also data for this and related code
; is defined at the end of this routine.
;-------------------------------------------------------------------------------
wild_settings proc near ; set switches variable by WILD= string
mov cs:ws_start,si ; save offset of WILD variable setting
xor bx,bx ; count here the number of characters
cld ; (for documentation and maintenance)
ws_next: lodsb
or al,al ; is it the null at end of ASCIIZ?
jz ws_search ; yes, capitalization is done
inc bx ; count it
cmp al,'a' ; is it below an 'a'?
jb ws_next ; yes, continue
cmp al,'z' ; is it above a 'z'?
ja ws_next ; yes, continue
and bptr [si-1],0dfh; capitalize it
jmp short ws_next ; continue
ws_search: mov si,cs:ws_start ; get start of WILD variables
mov di,of query ; search for QUERY
mov dx,query_size ; size of query string
call search_str ; do the search
jc do_noext ; QUERY not found; look for NOEXT
or cs:switches,que ; set bit 0 to indicate QUERY found
do_noext: mov si,cs:ws_start ; get start of WILD variables
mov di,of noext ; search for NOEXT
mov dx,noext_size ; size of query string
call search_str ; do the search
jc do_hidden ; no NOEXT; look for hidden switch
or cs:switches,noe ; set bit 1 to indicate NOEXT found
do_hidden: mov si,cs:ws_start ; get start of WILD variables
mov di,of hidden ; search for hidden string
mov dx,hidden_size ; size of hidden string
call search_str ; do the search
jc do_system ; no hidden; look for system switch
or cs:file_attr,hid; set bit 1 in file attribute
do_system: mov si,cs:ws_start ; get start of WILD variables
mov di,of system ; search for system string
mov dx,system_size ; size of system string
call search_str ; do the search
jc do_direct ; no system; look for direct switch
or cs:file_attr,sys; set bit 2 in file attribute
do_direct: mov si,cs:ws_start ; get start of WILD variables
mov di,of direct ; search for direct string
mov dx,direct_size ; size of direct string
call search_str ; do the search
jc ws_done ; no direct; all done
or cs:file_attr,dir; set bit 4 in file attribute
ws_done: ret
ws_start dw ? ; pointer to start of WILD env variables
query db 'QUERY' ; string to find in WILD env variable
query_size equ $-query
noext db 'NOEXT' ; another string to find
noext_size equ $-noext
hidden db 'H' ; find this, then include hidden files
hidden_size equ $-hidden
system db 'S' ; find this, then include system files
system_size equ $-system
direct db 'D' ; find this, then directory files
direct_size equ $-direct
que equ 1 ; set into switches if QUERY present
noe equ 2 ; set into switches if NOEXT present
hid equ 2 ; set into file_attr if hidden string
sys equ 4 ; set into file_attr if system string
dir equ 16 ; set into file_attr if direct string
wild_settings endp
;-------------------------------------------------------------------------------
; Find the size of the environment so only this number of bytes will be searched
; for environment strings.
;-------------------------------------------------------------------------------
find_env_size: mov ax,env_seg ; segment of environment --> es
mov es,ax
xor di,di ; search begins at start of environment
xor al,al ; search for nulls in environment
mov cx,8000h ; environment is no larger than 32k
next_word: repne scasb ; find a null
scasb ; a double null here?
jz found_env_end ; yes, signals end of environment block
jmp short next_word ; else continue searching
found_env_end: mov ax,8000h ; number of bytes in environment --> cx
xchg ax,cx
sub cx,ax
mov env_size,cx ; store size of our environment
;-------------------------------------------------------------------------------
; Setup segment registers for environment searches.
;-------------------------------------------------------------------------------
mov ax,env_seg ; segment of environment --> ds
mov ds,ax
push cs ; cs --> es
pop es
jmp short wild_env ; handle wild environment variables
;-------------------------------------------------------------------------------
; First search for the string "WILD=" in the environment and if it is found,
; then set program switches depending upon what the WILD environment variable
; is set to.
;-------------------------------------------------------------------------------
wild_str db 'WILD=' ; WILD's environment variable string
wild_size equ $-wild_str ; size of "WILD=" string
wild_env: xor si,si ; point to start of environment
mov dx,wild_size ; characters in string "WILD=" --> dx
mov di,of wild_str ; address WILD environment string
mov bx,cs:env_size ; number of bytes to search for string
call search_str ; find WILD string (if present)
jc do_cspc ; WILD string not found; do COMSPEC
add si,wild_size ; point si to value of WILD variable
call wild_settings ; record switch settings in environment
;-------------------------------------------------------------------------------
; Now, search for "COMSPEC=" in the environment. If it is found, then it will
; be used to provide the copy of COMMAND.COM to be used for the EXEC call(s).
; If it is not found, then we exit with an error message.
;-------------------------------------------------------------------------------
do_cspc: mov bx,cs:env_size ; number of bytes to search for COMSPEC
xor si,si ; point to start of environment
mov dx,cspc_size ; characters in string "COMSPEC=" --> dx
mov di,of cspc_str ; address COMSPEC string
call search_str ; find COMSPEC string (if present)
jnc comspec_found ; no carry, COMSPEC string was found
mov dx,of no_comspec; tell can't find COMSPEC, then exit
jmp error_exit
comspec_found: add si,cspc_size ; make si point to COMSPEC value
mov wp cs:cspc_addr,si ; store comspec offset
mov wp cs:cspc_addr+2,ds ; store comspec segment
push cs ; cs --> ds
pop ds ; (now cs, ds, and es are all same)
call find_first ; find the first file in the directory
cmp ax,255 ; special return for no wild card found?
jne wild_found ; no, check if a file was found
mov dx,of none_wild ; send this message and end
jmp error_exit
wild_found: or ax,ax ; a file found?
jnz none_here ; no, say so and end
jmp find_rest ; yes, find the remainder of files
none_here: mov dx,of no_file ; address no file message
jmp error_exit
last: ; offset of end of program. Used to assure that all code is
; retained with memory modify operation at the start of code.
code ends
end begin